package com.lyr.query.dynamic.core.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.lyr.query.dynamic.core.domain.QueryCondition;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.util.CollectionUtils;

/**
 * SQL工具类
 *
 * @author zk
 * @date 2025/1/23
 */
public class SqlUtils {

    private SqlUtils() {
    }

    /**
     * 拼接查询条件
     *
     * @param conditions 查询条件集合
     * @return String 例如 (a = 1 and b = 2) or (c = 3 and d = 4)
     */
    public static String getSqlWhereClause(List<QueryCondition> conditions) {
        if (CollectionUtils.isEmpty(conditions)) {
            return null;
        }
        StringBuilder buffer = new StringBuilder();
        for (QueryCondition condition : conditions) {
            // 判断值类型，如果是字符串则加上单引号
            handleSqlType(buffer, condition);
        }
        return buffer.toString();
    }

    /**
     * 拼接查询条件
     *
     * @param conditions 查询条件集合
     * @param clazz      数据实体类，用于字段校验
     * @return String 例如 (a = 1 and b = 2) or (c = 3 and d = 4)
     */
    public static String getSqlWhereClause(List<QueryCondition> conditions, Class<?> clazz) {
        if (CollectionUtils.isEmpty(conditions)) {
            return null;
        }
        StringBuilder buffer = new StringBuilder();
        for (QueryCondition condition : conditions) {
            //校验字段
            FieldValidator.validateField(clazz, condition.getField());
            // 判断值类型，如果是字符串则加上单引号
            handleSqlType(buffer, condition);
        }
        return buffer.toString();
    }

    /**
     * 拼接查询条件
     *
     * @param conditions 查询条件集合
     * @param clazz      数据实体类，用于字段校验
     * @return String 例如 (a = 1 and b = 2) or (c = 3 and d = 4)
     */
    public static String getSqlWhereClause(List<QueryCondition> conditions, String alias, Class<?> clazz) {
        if (CollectionUtils.isEmpty(conditions)) {
            return null;
        }
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < conditions.size(); i++) {
            QueryCondition condition = conditions.get(i);
            //校验字段
            FieldValidator.validateField(clazz, condition.getField());
            //如果是驼峰，则转为下划线
            condition.setField(StringUtils.camelToUnderline(condition.getField()));
            if (!alias.isEmpty()) {
                condition.setTableAlias(alias);
            }
            // 判断值类型，如果是字符串则加上单引号
            handleSqlType(buffer, condition);
            // 添加 AND 关键字，如果不是最后一个条件
            if (i < conditions.size() - 1) {
                buffer.append(" AND ");
            }
        }
        return buffer.toString();
    }

    /**
     * 处理sql的value类型，根据valueType进行相应处理
     *
     * @param buffer    sql语句
     * @param condition 查询条件
     */
    private static void handleSqlType(StringBuilder buffer, QueryCondition condition) {
        List<String> operators = Arrays.asList("in", "between", "like");
        buffer.append(" (").append(condition.getFullFieldName()).append(" ");
        // 首先优先处理显式指明了的  in、between、like 的操作类型
        if (operators.contains(condition.getOperator())) {
            switch (condition.getOperator()) {
                case "like":
                    buffer.append(condition.getOperator()).append(" '%").append(condition.getValue()).append("%'");
                    break;
                case "in":
                    // 处理列表类型，转换为IN查询
                    handleCollectionValue(buffer, condition);
                    break;
                case "between":
                    handleBetween(buffer, condition);
                    break;
                default:
                    // 对于未知类型，默认作为字符串处理
                    buffer.append(condition.getOperator()).append(" '").append(condition.getValue()).append("'");
            }
            buffer.append(") ");
            return;
        }
        // 其次动态检查值是否为集合类型，如果是且未特殊声明操作符为 between 范围处理 则隐式处理为IN查询
        if (isCollectionValue(condition.getValue())) {
            handleCollectionValue(buffer, condition);
            buffer.append(") ");
            return;
        }
        // 如果valueType为空，则使用原来的逻辑
        if (condition.getValueType() == null) {
            buffer.append(condition.getOperator()).append(" ");
            if (condition.getValue() instanceof String) {
                buffer.append("'").append(condition.getValue()).append("'");
            } else {
                buffer.append(condition.getValue());
            }
            buffer.append(") ");
        }

        // 根据valueType处理不同类型
        //        switch (condition.getValueType().toLowerCase()) {
        //            case "array":
        //                // 处理列表类型，转换为IN查询
        //                handleCollectionValue(buffer, condition);
        //                break;
        //            case "date":
        //                handleBetween(buffer, condition);
        //                break;
        //            case "string":
        //                buffer.append(condition.getOperator()).append(" '").append(condition.getValue()).append("'");
        //                break;
        //            case "integer":
        //            case "long":
        //            case "double":
        //            case "float":
        //            case "decimal":
        //                buffer.append(condition.getOperator()).append(" ").append(condition.getValue());
        //                break;
        //            case "boolean":
        //                buffer.append(condition.getOperator()).append(" ").append(Boolean.parseBoolean(condition.getValue().toString()) ? "1" : "0");
        //                break;
        //            default:
        //                // 对于未知类型，默认作为字符串处理
        //                buffer.append(condition.getOperator()).append(" '").append(condition.getValue()).append("'");
        //        }

        //        buffer.append(") ");
    }

    /**
     * 判断值是否为集合类型
     */
    private static boolean isCollectionValue(Object value) {
        return value instanceof Collection || (value != null && value.getClass().isArray()) || (value instanceof Object[] && ((Object[])value).length > 0);
    }

    /**
     * 处理集合类型的值，转换为IN查询
     */
    private static void handleCollectionValue(StringBuilder buffer, QueryCondition condition) {
        Object value = condition.getValue();
        Collection<?> valueCollection;

        if (value instanceof Collection) {
            valueCollection = (Collection<?>)value;
        } else if (value instanceof Object[]) {
            valueCollection = Arrays.asList((Object[])value);
        } else if (value.getClass().isArray()) {
            // 处理基本类型数组
            if (value instanceof int[]) {
                valueCollection = Arrays.stream((int[])value).boxed().collect(Collectors.toList());
            } else if (value instanceof long[]) {
                valueCollection = Arrays.stream((long[])value).boxed().collect(Collectors.toList());
            } else if (value instanceof double[]) {
                valueCollection = Arrays.stream((double[])value).boxed().collect(Collectors.toList());
            } else {
                throw new IllegalArgumentException("不支持的数组类型");
            }
        } else {
            throw new IllegalArgumentException("集合类型的值必须是Collection、数组或基本类型数组");
        }

        if (valueCollection.isEmpty()) {
            buffer.append("IN (null)");  // 处理空集合的情况
            return;
        }

        buffer.append("IN (");
        boolean first = true;
        for (Object item : valueCollection) {
            if (!first) {
                buffer.append(", ");
            }
            if (item instanceof String) {
                buffer.append("'").append(item).append("'");
            } else {
                buffer.append(item);
            }
            first = false;
        }
        buffer.append(")");
    }

    /**
     * 处理范围类型的值
     */
    private static void handleBetween(StringBuilder buffer, QueryCondition condition) {
        if ("between".equalsIgnoreCase(condition.getOperator())) {
            if (!(condition.getValue() instanceof List)) {
                throw new IllegalArgumentException("范围查询的值必须是数组");
            }
            List<?> dateRange = (List<?>)condition.getValue();
            if (dateRange.size() != 2) {
                throw new IllegalArgumentException("范围查询必须提供起止两个值");
            }
            buffer.append("BETWEEN '").append(dateRange.get(0)).append("' AND '").append(dateRange.get(1)).append("'");
        } else {
            buffer.append(condition.getOperator()).append(" '").append(condition.getValue()).append("'");
        }
    }

    /**
     * 拼接查询条件
     *
     * @param sql         原始sql语句
     * @param whereClause 查询条件
     * @return String 例如 select * from table where (a = 1) and (b = 2)
     */
    public static String concatSqlWhereClause(String sql, String whereClause) {
        // 查找外层 WHERE 子句（不在括号内）的起始位置
        int outerWhereIndex = findKeywordIndex(sql, "where");
        if (outerWhereIndex != -1) {
            // 如果存在外层 WHERE，则定位其条件部分结束的位置
            // 从 outerWhereIndex 之后开始查找外层 GROUP BY 或 ORDER BY 的位置
            int insertionPoint = findKeywordIndex(sql, "group by", outerWhereIndex);
            if (insertionPoint == -1) {
                insertionPoint = findKeywordIndex(sql, "order by", outerWhereIndex);
            }
            if (insertionPoint == -1) {
                insertionPoint = sql.length();
            }

            // 计算 WHERE 关键字后开始的位置（跳过 "where" 及后面的空白）
            int conditionsStart = outerWhereIndex + 5; // "where" 长度为5
            while (conditionsStart < sql.length() && Character.isWhitespace(sql.charAt(conditionsStart))) {
                conditionsStart++;
            }

            // 获取现有的 WHERE 条件部分（可能非常复杂）
            String existingConditions = sql.substring(conditionsStart, insertionPoint).trim();
            String combinedConditions;
            if (existingConditions.isEmpty()) {
                combinedConditions = whereClause;
            } else {
                // 为避免因优先级问题影响条件判断，最好用括号明确原有条件和新条件的关系
                combinedConditions = "(" + existingConditions + ") AND (" + whereClause + ")";
            }

            // 拼接新 SQL：原始的前半部分（包括 "where" 关键字及之后的空白） + 新的条件 + 后续部分（例如 GROUP BY/ORDER BY 子句）
            return sql.substring(0, conditionsStart) + combinedConditions + " " + sql.substring(insertionPoint);
        } else {
            // 如果不存在外层 WHERE，则在外层 GROUP BY 或 ORDER BY 之前插入 WHERE 子句（如果存在），否则追加到末尾
            int insertionPoint = findKeywordIndex(sql, "group by");
            if (insertionPoint == -1) {
                insertionPoint = findKeywordIndex(sql, "order by");
            }
            if (insertionPoint == -1) {
                insertionPoint = sql.length();
            }
            String before = sql.substring(0, insertionPoint).trim();
            String after = sql.substring(insertionPoint).trim();
            return before + " WHERE " + whereClause + " " + after;
        }
    }

    /**
     * 在 SQL 中查找指定关键字（如 "where", "group by", "order by"）的外层位置（即不在括号内） 从 startIndex 开始搜索，关键字搜索不区分大小写，并要求关键字前后不是字母或数字（保证完整单词匹配）。
     */
    private static int findKeywordIndex(String sql, String keyword, int startIndex) {
        String lowerSql = sql.toLowerCase();
        String lowerKeyword = keyword.toLowerCase();
        int keywordLen = lowerKeyword.length();
        int parenCount = 0;

        for (int i = startIndex; i <= lowerSql.length() - keywordLen; i++) {
            char c = lowerSql.charAt(i);
            if (c == '(') {
                parenCount++;
            } else if (c == ')') {
                if (parenCount > 0) {
                    parenCount--;
                }
            }
            // 当不在括号内时检测关键字
            if (parenCount == 0 && lowerSql.startsWith(lowerKeyword, i)) {
                // 检查关键字前后是否为边界（开始或非字母数字），避免误匹配部分单词
                boolean validBefore = (i == 0) || !Character.isLetterOrDigit(lowerSql.charAt(i - 1));
                boolean validAfter = (i + keywordLen >= lowerSql.length()) || !Character.isLetterOrDigit(lowerSql.charAt(i + keywordLen));
                if (validBefore && validAfter) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 重载方法，从头开始查找指定关键字的外层位置
     */
    private static int findKeywordIndex(String sql, String keyword) {
        return findKeywordIndex(sql, keyword, 0);
    }

}
